| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 | 1× 1× 1× 1× 1× 1× 1× 1× 12× 12× 1× 1× 5× 532490× 309910× 309910× 242177× 67733× 2× 1067952× 1067940× 613721× 454219× 2× 2× 70× 70× 70× 24× 24× 24× 1× 24× 206× 24× | // polyfill for Math.trunc (IE11) Iif (!Math.trunc) { Math.trunc = function (v) { v = +v; return (v - v % 1) || (!isFinite(v) || v === 0 ? v : v < 0 ? -0 : 0); }; } import { Calendar } from './calendar'; import { JulianDate } from "./julian-date"; import { GregorianDate } from "./gregorian-date"; import * as XRegExp from 'xregexp'; import { fromRomanNumber } from './roman'; export type JulianDays = { days: number, unknownYear: boolean, unknownMonth: boolean, unknownDay: boolean } const MonthPatterns: { [date: number]: string } = { 1: '([ij]an(uar(y|ii?)|)|janvier)', 2: '(feb(ruar[yi]?|r|)|fevrier)', 3: '(march|mars|marti[ia]s?|mart?)', 4: '(a[pv]ril|aprilis|apr)', 5: '(ma[ijy]|maji)', 6: '[ij]ui?n(ias|ii|e|)', 7: '([ij]uillet|[ij]ul[iay]s?)', 8: '(se[cxk]t?|august(us|i|)|ao[uû]s?t|aug)', 9: 'sep(ti?emb(er|re|r|)|t|)', 10: 'o[ck]t(ob(er|re|r|)|)', 11: 'nov(emb(er|re|ris|r|)|)', 12: 'de[ck](emb(er|re|ris|r|)|)', } let CompiledMonthPatterns: { [date: number]: RegExp } = {} for (let month = 1; month <= 12; month++) { CompiledMonthPatterns[month] = new RegExp(`^${MonthPatterns[month]}\.?$`, 'i'); } const AnyMonthPattern = `(${Object.keys(MonthPatterns).map((_, index) => MonthPatterns[index + 1]).join('|')})\.?`; // Roman or Arabic number const NumberPattern = '([MDCLXVI]( ?[MDCLXVI])*|[0-9]+)'; const DateFormats: RegExp[] = [ '^(?<month>{month}) (?<day>{day})[\.,] (?<year>{year})\.?$', '^(?<month>{month}) (?<day>{day})(st|nd|rd|th)[,\.]? (?<year>{year})\.?$', '^(ad|) ?(?<day>{day})[\.,]? ?(?<month>{month})[\. ](ao\.?|a\.?c\.?|anno|an\.? christi|an\.?|a\.?|) ?(?<year>{year})\.?$', '^(le|ce|) ?(?<day>{day})\.? (de |d[’\']|)(?<month>{month})(,? l[’\']an|\.?) (?<year>{year})\.?$', '^[aàá]? ?(?<day>{day})\.? de (?<month>{month}) del? a[nn̄n̄]*o de (?<year>{year})\.?$' ].map((pattern) => XRegExp(pattern.replace('{month}', AnyMonthPattern) .replace('{day}', NumberPattern) .replace('{year}', NumberPattern), 'i')); export function isLeapYear(year: number | undefined, calendar: Calendar = 'gregorian') { Iif (year === undefined) { return false; } if (calendar == 'gregorian') { return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; } else { return year % 4 === 0 || year <= 0; } } export function createDate( year: number | undefined, month: number | undefined, day: number | undefined, calendar: Calendar = 'gregorian') { switch (calendar) { case 'gregorian': return new GregorianDate(year, month, day); case 'julian': return new JulianDate(year, month, day); } } export function createDateFromString(text: string, calendar: Calendar = 'gregorian') { switch (calendar) { case 'gregorian': return GregorianDate.fromString(text); case 'julian': return JulianDate.fromString(text); } } export function parseDateString(text: string) { for (const format of DateFormats) { const match = XRegExp.exec(text, format) as any; if (match) { const day = fromRomanNumber(match['day']), month = parseMonthString(match['month']), year = fromRomanNumber(match['year']); Iif (month === null) { return null; } return { day, month, year }; } } return null; } function parseMonthString(text: string) { for (let month = 1; month <= 12; month++) { if (CompiledMonthPatterns[month].test(text)) { return month; } } return null; } |